﻿using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DotNetStar.OpenSDK
{
    /// <summary>
    /// 提供对指定的 url 地址发送 HTTP 请求和处理 HTTP 响应的客户端。
    /// </summary>
    /// <seealso cref="System.IDisposable" />
    public sealed class ApiClient
    {
        /// <summary>
        /// 以异步方式执行指定请求的 Api 接口。
        /// </summary>
        /// <typeparam name="TResponse">响应的类型结果。</typeparam>
        /// <param name="apiRequest">要发送的 api 请求。</param>
        /// <param name="cancellationToken">用于取消当前任务的 <see cref="CancellationToken"/> 对象。</param>
        /// <param name="timeout">发送 HTTP 的超时时间，单位分钟。</param>
        /// <returns>
        /// 由 <see cref="ApiRequest{TResponse}" /> 实例自定义处理的响应结果。
        /// </returns>
        /// <exception cref="ArgumentNullException">apiRequest 不能是 null。</exception>
        /// <exception cref="SdkException">已取消当前执行操作
        /// -
        /// 响应结果不是 OK(200)</exception>
        public static async Task<TResponse> ExecuteAsync<TResponse>(ApiRequest<TResponse> apiRequest, CancellationToken cancellationToken = default(CancellationToken), int timeout=1)
        {
            if (apiRequest == null)
            {
                throw new ArgumentNullException(nameof(apiRequest));
            }

            apiRequest.VerifyApiRequest();
            
            using (var httpClient = new HttpClient())
            {
                httpClient.Timeout = TimeSpan.FromMinutes(timeout);
                httpClient.DefaultRequestHeaders.UserAgent.Add(new System.Net.Http.Headers.ProductInfoHeaderValue("DNS.OpenSDK", "1.0"));

                var httpRequest = new HttpRequestMessage
                {
                    Method = new HttpMethod(apiRequest.GetHttpMethod().Name)
                };

                dynamic args = apiRequest.GetCreatingArguments();
                
                if (httpRequest.Method == HttpMethod.Post)
                {
                    httpRequest.RequestUri = new Uri(apiRequest.RequestUrl);
                    httpRequest.Content = new StringContent(args, Encoding.UTF8, apiRequest.GetContentType().ContentType);
                }
                else
                {
                    httpRequest.RequestUri = new Uri($"{apiRequest.RequestUrl}?{args}");
                }


                try
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var response = await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseContentRead, cancellationToken);

                    try
                    {
                        response.EnsureSuccessStatusCode();
                    }
                    catch (HttpRequestException ex)
                    {
                        throw new SdkException($"请求的 api 要求返回状态码：{HttpStatusCode.OK.ToString()}({(int)HttpStatusCode.OK}){Environment.NewLine}当前状态码：{response.StatusCode.ToString()}({(int)response.StatusCode})", ex);
                    }

                    return apiRequest.ResponseHandler(response);
                }
                catch (OperationCanceledException ex)
                {
                    throw new SdkException("已取消当前执行操作", ex);
                }
            }
        }
        
       
    }
}
